package apollo

import (
	"fmt"
	"github.com/apolloconfig/agollo/v4"
	"github.com/apolloconfig/agollo/v4/constant"
	"github.com/apolloconfig/agollo/v4/env/config"
	"github.com/apolloconfig/agollo/v4/extension"
	"github.com/ghodss/yaml"
	"reflect"
	"strings"
)

const (
	apolloCluster = "dev"
	apolloTelnetAddr = "apollostatus.api.maoka.356yx.com:80"
	apolloIpAddr = "http://apollostatus.api.maoka.356yx.com/"


	// product id
	ProductIdAms = 0
	ProductIdCms = 0
	ProductIdLogin 			= 1001
	ProductIdLobby 			= 2001
	ProductIdTeenPatti 		= 200001		// teenPatti
	ProductIdSeven 			= 200002		// 7上7下
	ProductIdAndar 			= 200003		// 安达尔
	ProductIdHamster 		= 200004  		// 打地鼠
	ProductIdQquaman 		= 200005		// 海王
	ProductIdRummy 			= 200006		// rummy
	ProductIdJhandimunda 	= 200007		// 6个骰子
	ProductIdMaowang 		= 200008   		// 猫王归来
	ProductIdLuckyLoto 		= 200009		// loto
	ProductIdLonghu 		= 210001		// 龙虎
	ProductIdSaima 			= 210002		// 赛马
	ProductIdShuiguo 		= 210003		// 水果
)
var (
	Ports  indPortsConf
	Global indGlobalConf
	envNs  EnvNamespace
)

// 初始化Apollo
func InitApollo(env string, customAppId string, obj interface{}) error {
	var err error
	//if err = telnetCheck(apolloTelnetAddr); err != nil {
	//	return err
	//}
	if li := strings.Split(env, "."); len(li) > 1 {
		envNs = EnvNamespace(li[0])
	} else {
		envNs = EnvNamespace(env)
	}


	// 读公共配置
	readProperties(&Ports)
	readProperties(&Global)
	fmt.Println("读取公共配置成功")

	// 读custom配置, 暂时固定为yaml
	if obj != nil && customAppId != "" {
		if err = readYaml(customAppId, getNameSpace(true), obj); err != nil {
			return err
		}
		fmt.Println("读取custom配置成功")
	}

	return nil
}

// 获取namespace, 项目中都是yaml模式
func getNameSpace(isCustom bool) string {
	if isCustom {
		return string(envNs) + ".yaml"
	} else {
		return string(envNs)
	}
}

// get agollo.client
func getMaokaClient(appId string) (agollo.Client, error) {
	c := &config.AppConfig{
		AppID:          appId,
		Cluster:        apolloCluster,
		NamespaceName:  fmt.Sprintf("%s,%s", getNameSpace(true), getNameSpace(false)),
		IP:             apolloIpAddr,
		IsBackupConfig: false,
	}
	extension.AddFormatParser(constant.YAML, &Parser{})
	client, err := getAgolloClient(c)
	return client, err
}

// 读 yaml
func readYaml(customAppId string, namespace string, obj interface{}) error {
	client, err := getMaokaClient(customAppId)
	if err != nil {
		return err
	}
	cache := client.GetConfigCache(namespace)
	if cache == nil {
		return fmt.Errorf("getConfigCache error. customAppId:%v, namespace:%v", customAppId, namespace)
	}

	value, e := cache.Get("content")
	if e != nil {
		return e
	}
	err = yaml.Unmarshal([]byte(value.(string)), obj)
	return err
}

// 读 properties
func readProperties(propertiesPtr interface{}) {
	ps, ok := propertiesPtr.(properties)
	if !ok {
		panic(fmt.Sprintf("propertiesPtr not a properties, %v", propertiesPtr))
	}
	client, e := getMaokaClient(ps.GetAppId())
	if e != nil {
		panic(e)
	}
	cache := client.GetConfigCache(ps.GetNamespace(envNs))
	if cache == nil {
		panic(fmt.Sprintf("cache is null. namespace:%s", ps.GetNamespace(envNs)))
	}
	rType := reflect.TypeOf(propertiesPtr)
	rVal := reflect.ValueOf(propertiesPtr)
	if rType.Kind() == reflect.Ptr {
		rType = rType.Elem()
		rVal = rVal.Elem()
	} else {
		panic("inStructPtr must be ptr to struct")
	}

	count := rVal.NumField()
	for i := 0; i < count; i++ {
		t := rType.Field(i)
		f := rVal.Field(i)
		//fmt.Printf("readProperties. name:%v,type:%v\n", t.Name, f.Type().Name())

		switch f.Kind() {
		case reflect.String:
			f.Set(reflect.ValueOf(readString(cache, strings.ToLower(t.Name))))
		case reflect.Int:
			f.Set(reflect.ValueOf(readInt(cache, strings.ToLower(t.Name))))
		}
	}
}

// Parser properties转换器
type Parser struct {
}
// Parse 内存内容=>yml文件转换器
func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error) {
	m:=make(map[string]interface{})
	m["content"]=configContent
	return m, nil
}